import { ECamp } from '../Manager/CampManager';
import Base from "../Base/Base";
import CardBase, { ICardDataType } from "../Card/CardBase";
import { EM, EEventName } from '../Manager/EventManager';
/*
 * @features: 阵营控制基类
 * @description: 游戏中多个角色的阵营控制基类
 * @Date: 2020-08-12 23:28:52
 * @Author: judu233(769471424@qq.com)
 * @LastEditTime: 2021-09-12 15:41:30
 * @LastEditors: judu233
 */


const { ccclass, property } = cc._decorator;

/**阵营数据 */
export interface ICampDataType {
    /**阵营名字 */
    camp: ECamp;
}

/**  
    * @Title : 阵营的基类
    * @Description : 游戏中存放多个角色的阵营控制基类
 **/
@ccclass
export default class CampBase extends Base {
    /**存放卡牌的组件列表*/
    @property([CardBase])
    public cardComList: CardBase[] = [];

    /**卡牌阵营信息 */
    public data: ICampDataType;

    /**卡牌的阵营名字*/
    public get camp(): ECamp {
        return this.checkGet(() => {
            return this.data.camp;
        });
    }
    public set camp(value: ECamp) {
        this.checkSet(() => {
            this.data.camp = value;
            this.campView(value);
        })
    }
    /**更新卡牌阵营视图 */
    protected campView(value: ECamp) { }

    /**所有卡牌的信息 */
    public cardList: CardBase[] = [];
    /**所有卡牌map */
    public cardMap: Map<string, CardBase> = new Map();
    /**阵营死亡的卡牌map */
    public deathMap: Map<string, CardBase> = new Map();
    /**阵营活着的卡牌map*/
    public surviveMap: Map<string, CardBase> = new Map();

    /**
     * 初始化阵营 
     * @param initData 要初始化的卡牌数据
     * @param campData 要初始化的阵营数据
     *  ! 组件查找顺序 -> 节点挂载 -> 节点的子节点查找
     */
    public initCamp(initData: ICardDataType[], campData: ICampDataType) {
        //初始化卡牌组件
        let cardList: CardBase[] = [];
        if (this.cardComList.length != 0) cardList = this.cardComList;
        else if (this.node.children.length > 0) {
            //尝试从节点下面或取卡牌
            for (let cardNode of this.node.children) {
                let card = cardNode.getComponent(CardBase);
                if (card) cardList.push(card);
            }
        } else cc.error(`[${this.className}]获取卡牌组件失败，请检查是否需要初始化or检查卡牌组件列表`);

        //初始化卡牌列表
        this.initCardList(cardList, initData);
        //初始化阵营数据
        if (campData) {
            this.data = campData;
            this.refreshCampView();
        } else cc.error(`[${this.className}]没有设置阵营数据！`);
    }

    /****************和阵营相关的接口*************** */
    /**更新阵营数据的所有视图 */
    public refreshCampView() {
        this.campView(this.data.camp);
    }

    /**检查所有卡牌是否死亡 */
    public checkCardAllDeath() {
        return this.surviveMap.size > 0 ? false : true;
    }

    /***************和卡牌相关的接口*************** */

    /**
     * 初始化卡牌列表 
     * @param cardLis 卡牌列表
     * @param initData 卡牌的初始化数据
     */
    public initCardList(cardLis: CardBase[], initData: ICardDataType[]) {
        //初始化卡牌
        this.cardList.length = 0;
        this.cardMap.clear();
        this.deathMap.clear();
        this.surviveMap.clear();
        for (let [index, card] of cardLis.entries()) {
            //设置数据
            card.data = initData[index];
            //存储
            this.cardList.push(card);
            this.surviveMap.set(card.id, card);
            this.cardMap.set(card.id, card);
            //初始化卡牌的技能模块
            card.initSkill();
            //更新卡牌的视图
            this.refreshCardView(card);
        }
    }

    /**
     * 更新卡牌所有数据的视图
     * @param card 更新视图的卡牌
     */
    public refreshCardView(card: CardBase) {
        card.refreshView();
    }

    /**获取卡牌列表的所有数据 */
    public getCardListData() {
        let cardData: ICampDataType[] = [];
        this.cardList.forEach(card => {
            cardData.push(card.data);
        })
        return cardData;
    }

    /**
     *  * 所有卡牌列表 相关的接口
     */
    /**
     * 根据卡牌名字从存储列表中返回卡牌
     * @param name 要获取卡牌的名字
     */
    public getCardByName(name: string) {
        for (let card of this.cardList) {
            if (card.itemName == name)
                return card;
        }
        cc.warn(`[${this.className}]根据名字获取卡牌${name}失败，请检查卡牌名字和卡牌列表！`);
    }

    /**
    * 根据卡牌id从存储列表中返回卡牌
    * @param name 要获取卡牌的名字
    */
    public getCardById(id: string) {
        for (let card of this.cardList) {
            if (card.id == id)
                return card;
        }
        cc.warn(`[${this.className}]根据id获取卡牌${id}失败，请检查卡牌id和卡牌列表！`);
    }

    /**
     *  *存活列表  相关的接口
     */
    /**
     * 根据名字从存活列表返回卡牌
     * @param name 要获取卡牌的卡牌名字
     */
    public getSurviveCardByName(name: string) {
        for (let surviveCard of this.surviveMap.values())
            if (name == surviveCard.itemName)
                return surviveCard;
        cc.warn(`[${this.className}]根据name获取[存活]卡牌${name}失败，请检查卡牌名name和卡牌列表`);
    }

    /**
     * 根据id从存活列表返回卡牌
     * @param name 要获取卡牌的卡牌名字
     */
    public getSurviveCardById(id: string) {
        return this.surviveMap.get(id) || cc.warn(`[${this.className}]根据id获取[存活]卡牌${id}失败，请检查卡牌名id和卡牌列表`);
    }

    /**
     * 从存活列表中删除卡牌，并存入死亡卡牌，且改变卡牌的状态
     * @param name 要删除存活卡牌的名字
     */
    public delSurviveCardByName(name: string) {
        if (this.surviveMap.delete(name)) {
            let card = this.cardMap.get(name);
            this.deathMap.set(name, card);
            //设置状态
            card.death = true;
            switch (this.camp) {
                case ECamp.Player:
                    EM.fire(EEventName.PlayerCardDeath);
                    break;
                case ECamp.Computer:
                    EM.fire(EEventName.ComputerCardDeath);
                    break;
                default:
                    cc.warn(`[${this.className}删除存活卡牌，发送事件失败，触发事件阵营：${this.camp}]`);
            }
        } else cc.warn(`[${this.className}]删除存活卡牌${name}失败，请检查卡牌名字和卡牌列表`);
    }

    /**
     * 从存活列表中随机获取指定数量的卡牌(最高返回列表所有卡牌)
     * @param count 要随机获取的数量
     */
    public getSurviveCardForRandom(count: number = 1) {
        let cardList = [...this.surviveMap.values()];
        let resultList: CardBase[] = [];
        for (let i = 0; i < count && cardList.length >= 1; i++) {
            let randomIndex = Math.floor(Math.random() * cardList.length);
            resultList.push(cardList.splice(randomIndex, 1)[0]);
        }
        return resultList;
    }

    /**
     *  * 死亡列表 相关的接口
     */
    /**
     * 根据名字返回死亡列表的卡牌
     * @param name 要获取卡牌的卡牌名字
     */
    public getDeathCardByName(name: string) {
        for (let deathCard of this.deathMap.values())
            if (name == deathCard.itemName)
                return deathCard;
        cc.warn(`[${this.className}]根据name获取[死亡]卡牌${name}失败，请检查卡牌名name和卡牌列表`);
    }

    /**
     * 根据id从死亡列表中获取卡牌
     * @param id 要获取的卡牌id
     */
    public getDeathCardById(id: string) {
        return this.deathMap.get(id) || cc.warn(`[${this.className}]根据id获取[死亡]卡牌${id}失败，请检查卡牌id和卡牌列表`);
    }

    /**
     * 从死亡列表中删除卡牌，并存入存活列表,且改变卡牌的状态
     * @param name 要删除死亡卡牌的名字
     */
    public delDeathCardByName(name: string) {
        if (this.deathMap.delete(name)) {
            let card = this.cardMap.get(name);
            this.surviveMap.set(name, card);
            //设置状态
            card.death = false;
            card.hp = card.hpUp;
            switch (this.camp) {
                case ECamp.Player:
                    EM.fire(EEventName.PlayerCardResurrection);
                    break;
                case ECamp.Computer:
                    EM.fire(EEventName.ComputerCardResurrection);
                    break;
                default:
                    cc.warn(`[${this.className}删除死亡卡牌，发送事件失败，触发事件阵营：${this.camp}]`);
            }
        } else cc.warn(`[${this.className}]删除死亡卡牌${name}失败，请检查卡牌名字和卡牌列表`);
    }

    /**
    * 从死亡列表中随机获取指定数量的卡牌(最高返回列表所有卡牌)
    * @param count 要随机获取的数量
    */
    public getDeathCardForRandom(count: number = 1) {
        let cardList = [...this.deathMap.values()];
        let resultList: CardBase[] = [];
        for (let i = 0; i < count && cardList.length >= 1; i++) {
            let randomIndex = Math.floor(Math.random() * cardList.length);
            resultList.push(cardList.splice(randomIndex, 1)[0]);
        }
        return resultList;
    }

}
